package com.jltx.xq.coroutinesapp

import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import kotlinx.android.synthetic.main.activity_main.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.await
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.*
import java.lang.Runnable
import kotlin.Exception
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

class MainActivity : AppCompatActivity(), View.OnClickListener {

    var tokenName: String? = null

    val mainViewModel by lazy {
        ViewModelProvider(this).get(MainViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        btn1.setOnClickListener(this)
        btn2.setOnClickListener(this)
        btn3.setOnClickListener(this)
        btn4.setOnClickListener(this)
        btn5.setOnClickListener(this)
        btn6.setOnClickListener(this)
        initListener()
    }

    override fun onClick(v: View?) {
        when (v?.id) {
            R.id.btn1 -> {
                coroutinesThreadTransform()
            }
            R.id.btn2 -> {
                getPictureCall()
            }
            R.id.btn3 -> {
                getPictureCallWithCoroutine()
            }
            R.id.btn4 -> {
                getPictureCallWithCancelCoroutine()
            }
            R.id.btn5 -> {
                getPictureCallKtWithCoroutine()
            }
            R.id.btn6 -> {
                mainViewModel.getPictureCallWithCoroutine()
            }
            else -> {
            }
        }
    }

    fun initListener() {
        mainViewModel.statusLiveData.observe(this, Observer {
            if (it) {
                showProgressBar()
            } else {
                hideProgressBar()
            }
        })

        mainViewModel.picListLiveData.observe(this, Observer {
            it?.apply {
                if (this.code > 0) {
                    showResult("获取图片数据成功: $it")
                } else {
                    showResult("获取图片数据失败")
                }
            }
        })
        btn6.setOnClickListener {
            Log.d("HHHH", "哒哒哒哒哒多" + it.id)
            println("HHHHH")
        }

        ceShi(Runnable {
            Log.d("HHHH", "哒哒哒哒哒多")
        })

    }

    private fun ceShi(runnable: Runnable) {
        runnable.run()
    }
    private fun showProgressBar() {
        progress.visibility = View.VISIBLE
        resultTv.text = "加载数据中。。。"
    }

    private fun hideProgressBar() {
        progress.visibility = View.GONE
    }

    private fun showResult(result: String) {
        resultTv.text = result
    }

    /**
     * 协程切换线程的优雅写法
     */
    private fun coroutinesThreadTransform() {
        lifecycleScope.launch {
            Log.d(TAG, "开始启动等待进度条 ${Thread.currentThread()}")
            showProgressBar()
            //io线程获取数据
            val token = withContext(Dispatchers.IO) {
                delay(600L)
                Log.d(TAG, "模拟获取token成功 ${Thread.currentThread()}")
                "aiquanquan"
            }
            //token缓存到数据
            tokenName = token
            //io获取logo数据成功
            val logo = getLogoUrl(token)
            //io获取titleName
            val titleName = async(Dispatchers.IO) {
                getTitleName()
            }
            //关闭等待进度条
            hideProgressBar()
            //讲得到的结果组合展示在UI
            showResult(logo + titleName.await())
        }
    }

    private suspend fun getTitleName(): String {
        delay(500L)
        Log.d(TAG, "模拟获取标题名称成功 ${Thread.currentThread()}")
        return "标题名称"
    }

    private suspend fun getLogoUrl(token: String) =
        withContext(Dispatchers.IO) {
            delay(200L)
            Log.d(TAG, "模拟通过token去获取logo成功 ${Thread.currentThread()}")
            "${token}_获取logoUrl成功"
        }


    private suspend fun getTitleNameAsync(
        coroutineScope: CoroutineScope
    ) = coroutineScope.async(Dispatchers.IO) {
        getTitleName()
    }.await()


    private fun CoroutineScope.getTitleNameAsync() = async(Dispatchers.IO) {
        delay(500L)
        Log.d(TAG, "模拟获取标题名称成功 ${Thread.currentThread()}")
        "标题名称"
    }


    fun getPictureData() {
        GlobalScope.launch(Dispatchers.Main) {
            try {
                val result = RetrofitService.service.getPicturesAsync(1, 15).await().result
                Log.e(TAG, "result：$result")
            } catch (e: Exception) {
                Log.e(TAG, "异常：", e)
            }

        }
    }

    /**
     * 直接retrofit call请求
     */
    private fun getPictureCall() {
        showProgressBar()
        RetrofitService.service.getPicturesAsync(1, 15)
            .enqueue(object : Callback<OpenApiResponse<List<OpenApiPicture>>> {
                override fun onResponse(
                    call: Call<OpenApiResponse<List<OpenApiPicture>>>,
                    response: Response<OpenApiResponse<List<OpenApiPicture>>>
                ) {
                    Log.d(TAG, "getPictureCall.result：${response.body()}")
                    hideProgressBar()
                    showResult("获取图片数据成功: ${response.body()}")
                }

                override fun onFailure(
                    call: Call<OpenApiResponse<List<OpenApiPicture>>>,
                    t: Throwable
                ) {
                    Log.e(TAG, "getPictureCall.异常：", t)
                    hideProgressBar()
                    showResult("获取图片数据失败 ${t}")
                }
            })
    }

    /**
     * 协程的方式请求网络
     */
    private fun getPictureCallWithCoroutine() {
        lifecycleScope.launch {
            showProgressBar()
            try {
                val pictureList = withContext(Dispatchers.IO) {
                    getPictureCallWithoutCancelAwait()
                }
                hideProgressBar()
                showResult("获取图片数据成功: $pictureList")
            } catch (e: Exception) {
                hideProgressBar()
                showResult("获取图片数据失败 $e")
            }
        }
    }

    /**
     * 协程的方式请求网络
     */
    private fun getPictureCallWithCancelCoroutine() {
        lifecycleScope.launch {
            showProgressBar()
            try {
                val pictureList = withContext(Dispatchers.IO) {
                    getPictureCallAwait()
                }
                hideProgressBar()
                showResult("获取图片数据成功: $pictureList")
            } catch (e: Exception) {
                hideProgressBar()
                showResult("获取图片数据失败 $e")
            }
        }
    }

    /**
     * 协程的方式请求网络
     */
    private fun getPictureCallKtWithCoroutine() {
        lifecycleScope.launch {
            showProgressBar()
            try {
                val pictureList = RetrofitService.service.getPicturesAsync(1, 15).awaitKt()
                hideProgressBar()
                showResult("获取图片数据成功: $pictureList")
            } catch (e: Exception) {
                hideProgressBar()
                showResult("获取图片数据失败 $e")
            }
        }
    }

    /**
     * 不支持取消的挂起函数suspendCoroutine
     */
    private suspend fun getPictureCallWithoutCancelAwait(): OpenApiResponse<List<OpenApiPicture>> =
        suspendCoroutine { cont ->

            RetrofitService.service.getPicturesAsync(1, 15)
                .enqueue(object : Callback<OpenApiResponse<List<OpenApiPicture>>> {
                    override fun onResponse(
                        call: Call<OpenApiResponse<List<OpenApiPicture>>>,
                        response: Response<OpenApiResponse<List<OpenApiPicture>>>
                    ) {
                        if (response.isSuccessful) {
                            cont.resume(response.body()!!)
                        } else {
                            cont.resumeWithException(Exception("data is error"))
                        }
                    }

                    override fun onFailure(
                        call: Call<OpenApiResponse<List<OpenApiPicture>>>,
                        t: Throwable
                    ) {
                        cont.resumeWithException(t)
                    }
                })
        }

    /**
     *  支持取消的挂起函数
     * 支持挂起函数的取消和不支持取消的差异点在于：
     * 使用suspendCancellableCoroutine{}
     * 需要调用Call的取消方法cancel()，也就是被扩展的取消方法，这里的cancel是retrofit中的。
     */
    private suspend fun getPictureCallAwait(): OpenApiResponse<List<OpenApiPicture>> =
        suspendCancellableCoroutine { cont ->
            val call = RetrofitService.service.getPicturesAsync(1, 15)
            cont.invokeOnCancellation {
                call.cancel()
            }
            call.enqueue(object : Callback<OpenApiResponse<List<OpenApiPicture>>> {
                override fun onResponse(
                    call: Call<OpenApiResponse<List<OpenApiPicture>>>,
                    response: Response<OpenApiResponse<List<OpenApiPicture>>>
                ) {
                    if (response.isSuccessful) {
                        cont.resumeWith(Result.success(response.body()!!))
                    } else {
                        cont.resumeWith(Result.failure(Exception("data is error")))
                    }
                }

                override fun onFailure(
                    call: Call<OpenApiResponse<List<OpenApiPicture>>>,
                    t: Throwable
                ) {
                    cont.resumeWith(Result.failure(Exception("data is error")))
                }
            })
        }

    companion object {
        private const val TAG = "aidenquan"
    }
}
